package main

import (
	"net/http"
	//导入echo包
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"crypto/x509"
	"encoding/asn1"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"

	"github.com/hyperledger/fabric/bccsp/utils"
	"github.com/labstack/echo"
)

func main() {
	//实例化echo对象。
	e := echo.New()

	//注册一个Get请求, 路由地址为: /tizi365  并且绑定一个控制器函数, 这里使用的是闭包函数。
	e.POST("/", HashTest)
	e.POST("/sign", GetSignData)
	//启动http server, 并监听8080端口，冒号（:）前面为空的意思就是绑定网卡所有Ip地址，本机支持的所有ip地址都可以访问。
	e.Start(":8066")
}

type Respon struct {
	Message string `json:"message"`
	Code    int    `json:"code"`
	Content string `json:"content"`
}

// HashTest
func HashTest(c echo.Context) error {
	// key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)

	// rawKey, _ := privateKeyToPEM(key, nil)

	// data := []byte("123")
	// sig, _ := SignData(key, data)

	// // 转换
	// pubKey1 := &key.PublicKey
	// b, _ := ECDSAPubToBase64(pubKey1)
	// fmt.Println("publicKey:", b)
	// if err != nil {
	// 	fmt.Println("ss")

	// }
	// fmt.Println("PubKey Base64 str : ", b)
	// pubKey2, _ := Base64ToECDSAPub(b)

	// // 验证
	// if VerifySignature(data, sig, pubKey1) {
	// 	fmt.Println("verify 1 success")
	// } else {
	// 	fmt.Println("verify failed")
	// }
	// if VerifySignature(data, sig, pubKey2) {
	// 	fmt.Println("verify 2 success")
	// } else {
	// 	fmt.Println("verify failed")
	// }
	pub := c.FormValue("pubBase")
	priBase := c.FormValue("priBase")
	content := c.FormValue("content")

	privateKey, _ := Base64ToBytes(priBase)

	// priBase := BytesToBase64(rawKey)
	// fmt.Println("privateKey:", priBase)
	keyFromPem, _ := parsePrivateKeyPEM(privateKey)

	res, _ := SignData(keyFromPem, []byte(content))
	pubKey, _ := Base64ToECDSAPub(pub)

	isValit := VerifySignature([]byte(content), res, pubKey)

	if isValit {
		return c.HTML(http.StatusOK, "success")
	}
	// key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	// //以Html页面的形式响应请求
	fmt.Println(pubKey)
	fmt.Println(keyFromPem)
	fmt.Println(res)
	// stringKey, _ := ECDSAPubToBase64(&key.PublicKey)
	return c.HTML(http.StatusOK, "ss")
}

func GetSignData(c echo.Context) error {
	priBase := c.FormValue("priBase")
	content := c.FormValue("content")

	privateKey, _ := Base64ToBytes(priBase)

	// priBase := BytesToBase64(rawKey)
	// fmt.Println("privateKey:", priBase)
	keyFromPem, _ := parsePrivateKeyPEM(privateKey)

	res, _ := SignData(keyFromPem, []byte(content))
	var resopn Respon
	resopn.Code = 200
	resopn.Content = BytesToBase64(res)
	resopn.Message = "success"

	data, _ := json.Marshal(resopn)
	return c.HTML(http.StatusOK, string(data))
}

// Hash sha256s
func Hash(data []byte) (h []byte, err error) {
	if data == nil {
		err = errors.New("hash data empty")
		return
	}
	sha256Inst := sha256.New()
	_, err = sha256Inst.Write(data)
	if err != nil {
		return
	}
	h = sha256Inst.Sum(nil)
	return
}

// SignData :
func SignData(priKey *ecdsa.PrivateKey, data []byte) (sig []byte, err error) {
	h, err := Hash(data)
	if err != nil {
		return
	}
	r, s, err := ecdsa.Sign(rand.Reader, priKey, h)
	if err != nil {
		return
	}
	return utils.MarshalECDSASignature(r, s)
}

// VerifySignature ：
func VerifySignature(data, sig []byte, pub *ecdsa.PublicKey) bool {
	h, err := Hash(data)
	if err != nil {
		return false
	}
	r, s, err := utils.UnmarshalECDSASignature(sig)
	if err != nil {
		return false
	}
	return ecdsa.Verify(pub, h, r, s)
}

// BytesToBase64 ：
func BytesToBase64(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

// Base64ToBytes :
func Base64ToBytes(s string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(s)
}

// Base64ToECDSAPub :
func Base64ToECDSAPub(s string) (pubKey *ecdsa.PublicKey, err error) {
	buf, err := Base64ToBytes(s)
	if err != nil {
		return
	}
	publicKeyInterface, err := x509.ParsePKIXPublicKey(buf)
	if err != nil {
		return
	}
	pubKey = publicKeyInterface.(*ecdsa.PublicKey)
	return
}

// ECDSAPubToBase64 :
func ECDSAPubToBase64(pubKey *ecdsa.PublicKey) (s string, err error) {
	block, err := x509.MarshalPKIXPublicKey(pubKey)
	if err != nil {
		return
	}
	s = BytesToBase64(block)
	return
}

// func pemToPrivateKey(raw []byte, pwd []byte) (interface{}, error) {
// 	block, _ := pem.Decode(raw)
// 	if block == nil {
// 		return nil, fmt.Errorf("failed decoding PEM. Block must be different from nil [% x]", raw)
// 	}
// 	// TODO: derive from header the type of the key
// 	if x509.IsEncryptedPEMBlock(block) {
// 		if len(pwd) == 0 {
// 			return nil, errors.New("encrypted Key. Need a password")
// 		}
// 		decrypted, err := x509.DecryptPEMBlock(block, pwd)
// 		if err != nil {
// 			return nil, fmt.Errorf("failed PEM decryption: [%s]", err)
// 		}
// 		key, err := derToPrivateKey(decrypted)
// 		if err != nil {
// 			return nil, err
// 		}
// 		return key, err
// 	}
// 	cert, err := derToPrivateKey(block.Bytes)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return cert, err
// }

// func derToPrivateKey(der []byte) (key interface{}, err error) {

// 	if key, err = x509.ParsePKCS1PrivateKey(der); err == nil {
// 		return key, nil
// 	}
// 	if key, err = x509.ParsePKCS8PrivateKey(der); err == nil {
// 		switch key.(type) {
// 		case *ecdsa.PrivateKey:
// 			return
// 		default:
// 			return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
// 		}
// 	}
// 	if key, err = x509.ParseECPrivateKey(der); err == nil {
// 		return
// 	}
// 	return nil, errors.New("invalid key type. The DER must contain an ecdsa.PrivateKey")
// }

func parsePrivateKeyPEM(rawKey []byte) (*ecdsa.PrivateKey, error) {
	block, _ := pem.Decode(rawKey)
	if block == nil {
		return nil, errors.New("bytes are not PEM encoded")
	}
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, nil
	}
	priv, ok := key.(*ecdsa.PrivateKey)
	if !ok {
		return nil, errors.New("pem bytes do not contain an EC private key")
	}
	return priv, nil
}

type pkcs8Info struct {
	Version             int
	PrivateKeyAlgorithm []asn1.ObjectIdentifier
	PrivateKey          []byte
}

type ecPrivateKey struct {
	Version       int
	PrivateKey    []byte
	NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
	PublicKey     asn1.BitString        `asn1:"optional,explicit,tag:1"`
}

var (
	oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
	oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
	oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
	oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
)

var oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}

func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
	switch curve {
	case elliptic.P224():
		return oidNamedCurveP224, true
	case elliptic.P256():
		return oidNamedCurveP256, true
	case elliptic.P384():
		return oidNamedCurveP384, true
	case elliptic.P521():
		return oidNamedCurveP521, true
	}
	return nil, false
}

func privateKeyToDER(privateKey *ecdsa.PrivateKey) ([]byte, error) {
	if privateKey == nil {
		return nil, errors.New("invalid ecdsa private key. It must be different from nil")
	}

	return x509.MarshalECPrivateKey(privateKey)
}

func privateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) {
	// Validate inputs
	if len(pwd) != 0 {
		return privateKeyToEncryptedPEM(privateKey, pwd)
	}
	if privateKey == nil {
		return nil, errors.New("invalid key. It must be different from nil")
	}

	switch k := privateKey.(type) {
	case *ecdsa.PrivateKey:
		if k == nil {
			return nil, errors.New("invalid ecdsa private key. It must be different from nil")
		}

		// get the oid for the curve
		oidNamedCurve, ok := oidFromNamedCurve(k.Curve)
		if !ok {
			return nil, errors.New("unknown elliptic curve")
		}

		// based on https://golang.org/src/crypto/x509/sec1.go
		privateKeyBytes := k.D.Bytes()
		paddedPrivateKey := make([]byte, (k.Curve.Params().N.BitLen()+7)/8)
		copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes)
		// omit NamedCurveOID for compatibility as it's optional
		asn1Bytes, err := asn1.Marshal(ecPrivateKey{
			Version:    1,
			PrivateKey: paddedPrivateKey,
			PublicKey:  asn1.BitString{Bytes: elliptic.Marshal(k.Curve, k.X, k.Y)},
		})

		if err != nil {
			return nil, fmt.Errorf("error marshaling EC key to asn1: [%s]", err)
		}

		var pkcs8Key pkcs8Info
		pkcs8Key.Version = 0
		pkcs8Key.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 2)
		pkcs8Key.PrivateKeyAlgorithm[0] = oidPublicKeyECDSA
		pkcs8Key.PrivateKeyAlgorithm[1] = oidNamedCurve
		pkcs8Key.PrivateKey = asn1Bytes

		pkcs8Bytes, err := asn1.Marshal(pkcs8Key)
		if err != nil {
			return nil, fmt.Errorf("error marshaling EC key to asn1: [%s]", err)
		}
		return pem.EncodeToMemory(
			&pem.Block{
				Type:  "PRIVATE KEY",
				Bytes: pkcs8Bytes,
			},
		), nil

	default:
		return nil, errors.New("invalid key type. It must be *ecdsa.PrivateKey")
	}
}

func privateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error) {
	if privateKey == nil {
		return nil, errors.New("invalid private key. It must be different from nil")
	}

	switch k := privateKey.(type) {
	case *ecdsa.PrivateKey:
		if k == nil {
			return nil, errors.New("invalid ecdsa private key. It must be different from nil")
		}
		raw, err := x509.MarshalECPrivateKey(k)

		if err != nil {
			return nil, err
		}

		block, err := x509.EncryptPEMBlock(
			rand.Reader,
			"PRIVATE KEY",
			raw,
			pwd,
			x509.PEMCipherAES256)

		if err != nil {
			return nil, err
		}

		return pem.EncodeToMemory(block), nil

	default:
		return nil, errors.New("invalid key type. It must be *ecdsa.PrivateKey")
	}
}

func derToPrivateKey(der []byte) (key interface{}, err error) {

	if key, err = x509.ParsePKCS1PrivateKey(der); err == nil {
		return key, nil
	}

	if key, err = x509.ParsePKCS8PrivateKey(der); err == nil {
		switch key.(type) {
		case *ecdsa.PrivateKey:
			return
		default:
			return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
		}
	}

	if key, err = x509.ParseECPrivateKey(der); err == nil {
		return
	}

	return nil, errors.New("invalid key type. The DER must contain an ecdsa.PrivateKey")
}

func pemToPrivateKey(raw []byte, pwd []byte) (interface{}, error) {
	block, _ := pem.Decode(raw)
	if block == nil {
		return nil, fmt.Errorf("failed decoding PEM. Block must be different from nil [% x]", raw)
	}

	// TODO: derive from header the type of the key

	if x509.IsEncryptedPEMBlock(block) {
		if len(pwd) == 0 {
			return nil, errors.New("encrypted Key. Need a password")
		}

		decrypted, err := x509.DecryptPEMBlock(block, pwd)
		if err != nil {
			return nil, fmt.Errorf("failed PEM decryption: [%s]", err)
		}

		key, err := derToPrivateKey(decrypted)
		if err != nil {
			return nil, err
		}
		return key, err
	}

	cert, err := derToPrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	return cert, err
}

func pemToAES(raw []byte, pwd []byte) ([]byte, error) {
	if len(raw) == 0 {
		return nil, errors.New("invalid PEM. It must be different from nil")
	}
	block, _ := pem.Decode(raw)
	if block == nil {
		return nil, fmt.Errorf("failed decoding PEM. Block must be different from nil [% x]", raw)
	}

	if x509.IsEncryptedPEMBlock(block) {
		if len(pwd) == 0 {
			return nil, errors.New("encrypted Key. Password must be different fom nil")
		}

		decrypted, err := x509.DecryptPEMBlock(block, pwd)
		if err != nil {
			return nil, fmt.Errorf("failed PEM decryption: [%s]", err)
		}
		return decrypted, nil
	}

	return block.Bytes, nil
}

func aesToPEM(raw []byte) []byte {
	return pem.EncodeToMemory(&pem.Block{Type: "AES PRIVATE KEY", Bytes: raw})
}

func aesToEncryptedPEM(raw []byte, pwd []byte) ([]byte, error) {
	if len(raw) == 0 {
		return nil, errors.New("invalid aes key. It must be different from nil")
	}
	if len(pwd) == 0 {
		return aesToPEM(raw), nil
	}

	block, err := x509.EncryptPEMBlock(
		rand.Reader,
		"AES PRIVATE KEY",
		raw,
		pwd,
		x509.PEMCipherAES256)

	if err != nil {
		return nil, err
	}

	return pem.EncodeToMemory(block), nil
}

func publicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) {
	if len(pwd) != 0 {
		return publicKeyToEncryptedPEM(publicKey, pwd)
	}

	if publicKey == nil {
		return nil, errors.New("invalid public key. It must be different from nil")
	}

	switch k := publicKey.(type) {
	case *ecdsa.PublicKey:
		if k == nil {
			return nil, errors.New("invalid ecdsa public key. It must be different from nil")
		}
		PubASN1, err := x509.MarshalPKIXPublicKey(k)
		if err != nil {
			return nil, err
		}

		return pem.EncodeToMemory(
			&pem.Block{
				Type:  "PUBLIC KEY",
				Bytes: PubASN1,
			},
		), nil

	default:
		return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey")
	}
}

func publicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) {
	switch k := publicKey.(type) {
	case *ecdsa.PublicKey:
		if k == nil {
			return nil, errors.New("invalid ecdsa public key. It must be different from nil")
		}
		raw, err := x509.MarshalPKIXPublicKey(k)
		if err != nil {
			return nil, err
		}

		block, err := x509.EncryptPEMBlock(
			rand.Reader,
			"PUBLIC KEY",
			raw,
			pwd,
			x509.PEMCipherAES256)

		if err != nil {
			return nil, err
		}

		return pem.EncodeToMemory(block), nil
	default:
		return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey")
	}
}

func pemToPublicKey(raw []byte, pwd []byte) (interface{}, error) {
	if len(raw) == 0 {
		return nil, errors.New("invalid PEM. It must be different from nil")
	}
	block, _ := pem.Decode(raw)
	if block == nil {
		return nil, fmt.Errorf("failed decoding. Block must be different from nil [% x]", raw)
	}

	// TODO: derive from header the type of the key
	if x509.IsEncryptedPEMBlock(block) {
		if len(pwd) == 0 {
			return nil, errors.New("encrypted Key. Password must be different from nil")
		}

		decrypted, err := x509.DecryptPEMBlock(block, pwd)
		if err != nil {
			return nil, fmt.Errorf("failed PEM decryption: [%s]", err)
		}

		key, err := derToPublicKey(decrypted)
		if err != nil {
			return nil, err
		}
		return key, err
	}

	cert, err := derToPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	return cert, err
}

func derToPublicKey(raw []byte) (pub interface{}, err error) {
	if len(raw) == 0 {
		return nil, errors.New("invalid DER. It must be different from nil")
	}

	key, err := x509.ParsePKIXPublicKey(raw)

	return key, err
}
